# -*- coding: utf-8 -*-

import struct
import tcp_msg_client


_g_forward_client_instance = None


# @Singleton
class ForwardClient(tcp_msg_client.TcpMsgClient):

    # __metaclass__ = Singleton

    BROADCAST_EID = -1
    NONE_EID = 0
    MAX_DST_NUM = 1024

    CMD_HEARTBEAT = 0
    CMD_LOGIN = 1
    CMD_LOGOUT = 2
    CMD_FORWARD = 3

    PICKLE_VERSION = 0

    # 报文格式：cmd, src, dst_num, [dst1, dst2, ..., payload]
    #          0   4   8        12     16

    def __init__(self):
        super(ForwardClient, self).__init__()
        self._self_eid = ForwardClient.NONE_EID
        self._cmd_proc = [[], [], [], []]    # 对应每个cmd，增加命令在此增加

    def bind_cmd_recv(self, cmd, func):         # func(src_eid, dst_eid_list, payload)
        if cmd < 0 or cmd >= len(self._cmd_proc):
            print("Bind invalid cmd: {}".format(cmd))
            return
        self._cmd_proc[cmd].append(func)

    def send_msg(self, cmd, src, dst_list, payload=''):     # 广播则dst_list为[BROADCAST_EID]
        msg = ForwardClient.make_msg(cmd, src, dst_list, payload)
        self.send(msg)

    def set_self_eid(self, self_eid):
        self._self_eid = self_eid

    def get_self_eid(self):
        return self._self_eid

    def recv_proc(self, msg):
        if len(msg) < 12:
            print("Data length too short = {}".format(msg))
            return
        cmd, src, dst_list, payload = ForwardClient._parse_msg(msg)
        if cmd < 0 or cmd >= len(self._cmd_proc):
            print("Recv invalid msg, cmd = {}".format(cmd))
            return
        for each_func in self._cmd_proc[cmd]:
            each_func(src, dst_list, payload)

    @staticmethod
    def _parse_msg(msg):  # return: cmd, src, dst_list, payload
        cmd, src, dst_num = struct.unpack('iii', msg[:12])
        if dst_num <= 0:
            dst_list = []
            next_pos = 12
        else:
            next_pos = 12 + 4 * dst_num
            if len(msg) < next_pos:
                print("Parse src dst error: dst list error, dst_num = {}".format(dst_num))
                return -1, 0, [], ""    # 解析错误
            dst_list = list(struct.unpack('i' * dst_num, msg[12: next_pos]))
        return cmd, src, dst_list, msg[next_pos:]

    @staticmethod
    def make_msg(cmd, src, dst_list, payload=''):
        header = struct.pack('i' * (3 + len(dst_list)), cmd, src, len(dst_list), *dst_list)
        return header + payload


# ForwardClient_Ins = ForwardClient()
# ForwardClient_Ins = None


def Get():
    return _g_forward_client_instance


def Set(obj=None):
    global _g_forward_client_instance
    _g_forward_client_instance = obj

